package ar.edu.utn.frsf.cidisi.ginet.generation.pnml2cpntools;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.naming.OperationNotSupportedException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.cpntools.accesscpn.model.ModelFactory;
import org.cpntools.accesscpn.model.cpntypes.CPNInt;
import org.cpntools.accesscpn.model.cpntypes.CpntypesFactory;
import org.cpntools.accesscpn.model.declaration.DeclarationFactory;
import org.cpntools.accesscpn.model.declaration.TypeDeclaration;
import org.cpntools.accesscpn.model.declaration.VariableDeclaration;
import org.cpntools.accesscpn.model.exporter.DOMGenerator;
import org.eclipse.emf.common.util.EList;
import org.pnml.tools.epnk.pnmlcoremodel.Object;
import org.pnml.tools.epnk.pntypes.hlpngs.datatypes.terms.UserSort;
import org.w3c.dom.Document;

import ar.edu.utn.frsf.cidisi.ginet.Arc;
import ar.edu.utn.frsf.cidisi.ginet.GINet;
import ar.edu.utn.frsf.cidisi.ginet.Place;
import ar.edu.utn.frsf.cidisi.ginet.Transition;

/**
 * @author jmr
 *
 */
public class Pnml2CpnTools {

	private org.cpntools.accesscpn.model.PetriNet cpn;
	private GINet pnmlNet;
	
	private HashMap<String,org.cpntools.accesscpn.model.Place> cpnPlaces = new HashMap<String,org.cpntools.accesscpn.model.Place>();

	private HashMap<String,org.cpntools.accesscpn.model.RefPlace> cpnRefPlaces = new HashMap<String,org.cpntools.accesscpn.model.RefPlace>();

	private HashMap<String,org.cpntools.accesscpn.model.Transition> cpnTransitions = new HashMap<String, org.cpntools.accesscpn.model.Transition>();
	
	public Pnml2CpnTools(GINet pn){
		pnmlNet = pn;
		
	}
	
	public void generateCPN(){
		
		cpn = ModelFactory.INSTANCE.createPetriNet();
		cpn.setId(pnmlNet.getId());
		org.cpntools.accesscpn.model.Name name = ModelFactory.INSTANCE.createName();
		name.setText(pnmlNet.getName().getText());
		cpn.setName(name);
		
		
		createGloboxDefinitions();
		
		createPages();
		
	}
	
	public void createGloboxDefinitions(){

		final ArrayList<org.cpntools.accesscpn.model.Label> labels = new ArrayList<org.cpntools.accesscpn.model.Label>();
		
		// Creation of colors GINT and CTRL.-
		
		// Color GINT
		final TypeDeclaration colorGINT = DeclarationFactory.INSTANCE.createTypeDeclaration();
		final CPNInt intType = CpntypesFactory.INSTANCE.createCPNInt();
		colorGINT.setSort(intType);
		colorGINT.setTypeName("GINT");
		
		final org.cpntools.accesscpn.model.HLDeclaration declINT = ModelFactory.INSTANCE.createHLDeclaration();
		declINT.setStructure(colorGINT);
		declINT.setId("idcolorgint");
		
		labels.add(declINT);

		
//		// Color CTRL
//		final TypeDeclaration colorCTRL = DeclarationFactory.INSTANCE.createTypeDeclaration();
//		final CPNInt ctrlType = CpntypesFactory.INSTANCE.createCPNInt();
//		colorCTRL.setSort(ctrlType);
//		colorCTRL.setTypeName("CTRL");
//		
//		final HLDeclaration declCTRL = ModelFactory.INSTANCE.createHLDeclaration();
//		declCTRL.setStructure(colorCTRL);
//		declCTRL.setId("idcolorctrl");
//		
//		labels.add(declCTRL);
//
//		// Color UNIT
//		final TypeDeclaration colorUNIT = DeclarationFactory.INSTANCE.createTypeDeclaration();
//		final CPNUnit unitType = CpntypesFactory.INSTANCE.createCPNUnit();
//		colorUNIT.setSort(unitType);
//		colorUNIT.setTypeName("UNIT");
//		
//		final HLDeclaration declUNIT = ModelFactory.INSTANCE.createHLDeclaration();
//		declUNIT.setStructure(colorUNIT);
//		declUNIT.setId("idcolorunit");
//		
//		labels.add(declUNIT);
		
		
		// Creation of variables gi and ctrl.-
		
		// Variable gi
		final VariableDeclaration varDeclgi = DeclarationFactory.INSTANCE.createVariableDeclaration();
		varDeclgi.addVariable("gi");
		varDeclgi.setTypeName("GINT");
		
		final org.cpntools.accesscpn.model.HLDeclaration declgi = ModelFactory.INSTANCE.createHLDeclaration();
		declgi.setStructure(varDeclgi);
		declgi.setId("idvargi");
		
		labels.add(declgi);
		
		
//		// Variable ctrl
//		final VariableDeclaration varDeclctrl = DeclarationFactory.INSTANCE.createVariableDeclaration();
//		varDeclctrl.addVariable("ctrl");
//		varDeclctrl.setTypeName("CTRL");
//		
//		final HLDeclaration declctrl = ModelFactory.INSTANCE.createHLDeclaration();
//		declctrl.setStructure(varDeclctrl);
//		declctrl.setId("idvarctrl");
//		
//		labels.add(declctrl);
		
		
		// Add each label to cpn.-
		for (final org.cpntools.accesscpn.model.Label label : labels) {
			label.setParent(cpn);
		}
		
		

	}
	
	private void createPages(){
		
		EList<org.pnml.tools.epnk.pnmlcoremodel.Page> pages = pnmlNet.getPage();
		
		for (org.pnml.tools.epnk.pnmlcoremodel.Page page : pages){
			
			org.cpntools.accesscpn.model.Page newPage = ModelFactory.INSTANCE.createPage();
			
			newPage.setId(page.getId());
			
			org.cpntools.accesscpn.model.Name pageName = ModelFactory.INSTANCE.createName();
			
			pageName.setText(page.getName().getText());
			
			newPage.setName(pageName);
			
			cpn.getPage().add(newPage);
			
			List<Object> objects = page.getObject();
			
			for (Object object : objects){
				
				if (object instanceof Place){
					
					org.cpntools.accesscpn.model.Place newPlace = createPlace((Place)object, newPage);
					
//					newPage.getObject().add(newPlace);
					
				} else if (object instanceof Transition){
					
					org.cpntools.accesscpn.model.Transition newTransition = createTransition((Transition)object, newPage);
					
				} else if (object instanceof Arc){
					
//					org.cpntools.accesscpn.model.Arc newArc = createArc((Arc)object, newPage);
				}
			}
		}
	}
	
	private org.cpntools.accesscpn.model.Place createPlace(Place place, org.cpntools.accesscpn.model.Page page){
		org.cpntools.accesscpn.model.Place newPlace = ModelFactory.INSTANCE.createPlace();
		newPlace.setId(place.getId());
		newPlace.setPage(page);
		org.cpntools.accesscpn.model.Name name = ModelFactory.INSTANCE.createName();
		name.setText(place.getName().getText());
		newPlace.setName(name);
		
		org.cpntools.accesscpn.model.Sort sort = ModelFactory.INSTANCE.createSort();
		if (place.getType() != null && place.getType().getStructure() instanceof UserSort){
			UserSort userSort = (UserSort)place.getType().getStructure();
			
			if (userSort.getDeclaration() != null)
				sort.setText(userSort.getDeclaration().getName());
			else
				sort.setText("");
		} else{
			sort.setText("");
		}

		newPlace.setSort(sort);
		
		org.cpntools.accesscpn.model.HLMarking marking = ModelFactory.INSTANCE.createHLMarking();
		marking.setText("");
		newPlace.setInitialMarking(marking);
		
		org.cpntools.accesscpn.model.graphics.NodeGraphics graphics = org.cpntools.accesscpn.model.graphics.GraphicsFactory.INSTANCE.createNodeGraphics();
		org.cpntools.accesscpn.model.graphics.Coordinate coordinate = org.cpntools.accesscpn.model.graphics.GraphicsFactory.INSTANCE.createCoordinate();
		double x = ((org.pnml.tools.epnk.pnmlcoremodel.NodeGraphics)place.getGraphics()).getPosition().getX();
		double y = ((org.pnml.tools.epnk.pnmlcoremodel.NodeGraphics)place.getGraphics()).getPosition().getY();
		coordinate.setX(x);
		coordinate.setY(y);
		graphics.setPosition(coordinate);
		newPlace.setGraphics(graphics);
		
		cpnPlaces.put(newPlace.getId(), newPlace);
		
		return newPlace;
	}

	private org.cpntools.accesscpn.model.Transition createTransition(Transition transition, org.cpntools.accesscpn.model.Page page){
		org.cpntools.accesscpn.model.Transition newTransition = ModelFactory.INSTANCE.createTransition();
		newTransition.setId(transition.getId());
		newTransition.setPage(page);
		org.cpntools.accesscpn.model.Name name = ModelFactory.INSTANCE.createName();
		name.setText(transition.getName().getText());
		newTransition.setName(name);
		
		org.cpntools.accesscpn.model.Condition cond = ModelFactory.INSTANCE.createCondition();
		cond.setText("");
		newTransition.setCondition(cond);
		
		org.cpntools.accesscpn.model.Code code = ModelFactory.INSTANCE.createCode();
		code.setText("");
		newTransition.setCode(code);
		
		org.cpntools.accesscpn.model.Time time = ModelFactory.INSTANCE.createTime();
		time.setText("");
		newTransition.setTime(time);

		org.cpntools.accesscpn.model.graphics.NodeGraphics graphics = org.cpntools.accesscpn.model.graphics.GraphicsFactory.INSTANCE.createNodeGraphics();
		org.cpntools.accesscpn.model.graphics.Coordinate coordinate = org.cpntools.accesscpn.model.graphics.GraphicsFactory.INSTANCE.createCoordinate();
		double x = ((org.pnml.tools.epnk.pnmlcoremodel.NodeGraphics)transition.getGraphics()).getPosition().getX();
		double y = ((org.pnml.tools.epnk.pnmlcoremodel.NodeGraphics)transition.getGraphics()).getPosition().getY();
		coordinate.setX(x);
		coordinate.setY(y);
		graphics.setPosition(coordinate);
		newTransition.setGraphics(graphics);
		
		cpnTransitions.put(newTransition.getId(), newTransition);

		return newTransition;
	}
	
	public org.cpntools.accesscpn.model.Arc createArc(ar.edu.utn.frsf.cidisi.ginet.Arc arc, org.cpntools.accesscpn.model.Page page){
		org.cpntools.accesscpn.model.Arc newArc = ModelFactory.INSTANCE.createArc();
		newArc.setId(arc.getId());
		newArc.setPage(page);
		
		org.cpntools.accesscpn.model.Name name = ModelFactory.INSTANCE.createName();
		if (arc.getName() != null )
			name.setText(arc.getName().getText());
		else
			name.setText("");

		if (arc.getSource() instanceof ar.edu.utn.frsf.cidisi.ginet.Place){  // If the arc's source is a place
			
			org.cpntools.accesscpn.model.Place source = cpnPlaces.get(((ar.edu.utn.frsf.cidisi.ginet.Place)arc.getSource()).getId());
			
			newArc.setSource(source);
			
			org.cpntools.accesscpn.model.Transition target = cpnTransitions.get(((ar.edu.utn.frsf.cidisi.ginet.Transition)arc.getTarget()).getId());
			
			newArc.setTarget(target);
			
		} else if (arc.getSource() instanceof ar.edu.utn.frsf.cidisi.ginet.Transition){  // If the arc's source is a transition
			
			org.cpntools.accesscpn.model.Transition source = cpnTransitions.get(((ar.edu.utn.frsf.cidisi.ginet.Transition)arc.getSource()).getId());
			
			newArc.setSource(source);

			// If the source of an arc is a transition, the target could be a place or a refPlace 
			if (arc.getTarget() instanceof ar.edu.utn.frsf.cidisi.ginet.Place){  // If the arc's target is a place
			
				org.cpntools.accesscpn.model.Place target = cpnPlaces.get(((ar.edu.utn.frsf.cidisi.ginet.Place)arc.getTarget()).getId());
				
				newArc.setTarget(target);
				
			} else if (arc.getTarget() instanceof org.pnml.tools.epnk.pnmlcoremodel.RefPlace){ // If the arc's target is a refPlace
				
				org.cpntools.accesscpn.model.RefPlace target = cpnRefPlaces.get(((org.pnml.tools.epnk.pnmlcoremodel.RefPlace)arc.getTarget()).getId());
				
				newArc.setTarget(target);

			}
		}
		
		
		org.cpntools.accesscpn.model.HLAnnotation annotation = ModelFactory.INSTANCE.createHLAnnotation();
		annotation.setText("");
//		AnnotationGraphics graphics = GraphicsFactory.INSTANCE.createAnnotationGraphics();
//		annotation.setGraphics(graphics);
//		Coordinate coordinate = GraphicsFactory.INSTANCE.createCoordinate();
//		double x = ((org.pnml.tools.epnk.pnmlcoremodel.AnnotationGraphics)arc.getHlinscription().getGraphics()).getOffset().getX();
//		double y = ((org.pnml.tools.epnk.pnmlcoremodel.AnnotationGraphics)arc.getHlinscription().getGraphics()).getOffset().getY();
//		coordinate.setX(x);
//		coordinate.setY(y);
//		annotation.getAnnotationGraphics().setOffset(coordinate);

//		graphics.setPosition(coordinate);
//		newTransition.setGraphics(graphics);
		
		if (arc.getHlinscription() != null){
			annotation.setText(arc.getHlinscription().getText());
			newArc.setHlinscription(annotation);
		}
		
		
//		Line line = GraphicsFactory.INSTANCE.createLine();
//		ArcGraphics graphics = GraphicsFactory.INSTANCE.createArcGraphics();
//		Coordinate coordinate = GraphicsFactory.INSTANCE.createCoordinate();
//		double x = ((org.pnml.tools.epnk.pnmlcoremodel.NodeGraphics)arc.getGraphics()).getPosition().getX();
//		double y = ((org.pnml.tools.epnk.pnmlcoremodel.NodeGraphics)arc.getGraphics()).getPosition().getY();
//		coordinate.setX(x);
//		coordinate.setY(y);
//		((ArcGraphics)arc.getGraphics()).getPosition().
//		graphics.setPosition(coordinate);
//		newTransition.setGraphics(graphics);



		return newArc;

		

	}

	
	public void export(String newFileName){
		try {
			
				Document doc = DOMGenerator.export(cpn,newFileName);
//				Document doc = DOMGenerator.export(pn);
//				write(doc, ResourcesPlugin.getWorkspace().getRoot().getLocation()+"/miPetriNet.cpn");
				System.out.println();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		} catch (OperationNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public org.cpntools.accesscpn.model.Place getPlace(String id){
		
		org.cpntools.accesscpn.model.Place place = null;
		
		
		return place;
	}
	

	
}
